/*
 * CAT - TAC Market Design Competition Server
 * Copyright (C) 2006-2009 Jinzhong Niu, Kai Cai
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 */

package twbb.market;

import org.apache.log4j.Logger;

import edu.cuny.ai.learning.SlidingWindowLearner;

import edu.cuny.cat.core.Specialist;
import edu.cuny.cat.core.IllegalShoutException;
import edu.cuny.cat.core.Shout;

import edu.cuny.cat.event.AuctionEvent;
import edu.cuny.cat.event.TransactionExecutedEvent;
import edu.cuny.cat.event.DayClosedEvent;

import edu.cuny.cat.stat.Score;
import edu.cuny.cat.stat.ScoreReport;
import edu.cuny.cat.stat.DailyAssessmentReport;
import edu.cuny.cat.stat.ReportVariableBoard;
import edu.cuny.util.Parameter;
import edu.cuny.util.ParameterDatabase;

import edu.cuny.cat.market.QuoteBeatingAcceptingPolicy;

import twbb.adaptive.KnowledgeAdaptive;


/**
 * <p>
 * A variant of {@link EquilibriumBeatingAcceptingPolicy}, which was used by
 * PSUCAT in CAT 2007 competition. It uses a sliding average of transaction
 * prices to estimate the equilibrium price and uses the standard deviation to
 * set <code>delta</code> loosing the restriction.
 * </p>
 * 
 * @author Jinzhong Niu
 * @version $Revision: 1.2 $
 */

public class TWBB_SlidingAverageBeatingAcceptingPolicy extends
		QuoteBeatingAcceptingPolicy{

	static Logger logger = Logger
			.getLogger(TWBB_SlidingAverageBeatingAcceptingPolicy.class);

	/**
	 * Reusable exceptions for performance
	 */
	protected static IllegalShoutException bidException = null;

	protected static IllegalShoutException askException = null;

	protected double expectedHighestAsk;

	protected double expectedLowestBid;

	protected SlidingWindowLearner learner;

	public static final String P_LEARNER = "learner";

	public static final String P_DEF_BASE = "equilibrium_beating_accepting";

	public static final String SLIDING_AVERAGE_TRANSACTION_PRICE = "sliding.average.transaction.price";
	
	double k;
    double maxK = 0.1;
    double minK = 0;
    double stepK = 0.01;
	
	double lastTransactionRate;	
	double lastProfit;	
    double lastMarketShare;    
	double lastTotal;

    double currentTransactionRate;
    double currentProfit;
    double currentMarketShare;
    double currentTotal;

    protected String roundPeriod;
	
	ScoreReport scoreReport = null;
    protected Specialist specialist;
    protected DailyAssessmentReport dailyScores;
    protected KnowledgeAdaptive knowledgeAdaptive;
    private Object scoreDaysCondition;


	public TWBB_SlidingAverageBeatingAcceptingPolicy() {
		learner = new SlidingWindowLearner();
		//scoreReport = new ScoreReport();
	}

    @Override
	public void setup(ParameterDatabase parameters, Parameter base) {
		super.setup(parameters, base);

		learner.setup(parameters, base.push(P_LEARNER));

	}

  
    @Override
	public void initialise() {
		expectedHighestAsk = Double.MAX_VALUE;
		expectedLowestBid = 0;
		
		k = 0.05;
	}

    @Override
	public void reset() {
		super.reset();

		initialise();

		learner.reset();
	}

    @Override
	public void check(Shout shout) throws IllegalShoutException {
		super.check(shout);

		if (shout.isAsk()) {
			if (shout.getPrice() > expectedHighestAsk) {
				askNotAnImprovementException();
			}
		} else {
			if (shout.getPrice() < expectedLowestBid) {
				bidNotAnImprovementException();
			}
		}
	}

	protected void bidNotAnImprovementException() throws IllegalShoutException {
		if (bidException == null) {
			// Only construct a new exception the once (for improved performance)
			bidException = new IllegalShoutException(
					"Bid cannot beat the estimated equilibrium!");
		}
		throw bidException;
	}

	protected void askNotAnImprovementException() throws IllegalShoutException {
		if (askException == null) {
			// Only construct a new exception the once (for improved performance)
			askException = new IllegalShoutException(
					"Ask cannot beat the estimated equilibrium!");
		}
		throw askException;
	}


    public void eventOccurred(AuctionEvent event)
    {
        super.eventOccurred(event);
        if (event instanceof TransactionExecutedEvent)
            transactionExecuted(event);
        else if(event instanceof DayClosedEvent)
            dayClosed(event);
        else if(event instanceof TransactionExecutedEvent)
            transactionExecuted(event);
    }

	
    private void transactionExecuted(AuctionEvent event) {
		learner.train(((TransactionExecutedEvent) event).getTransaction()
					.getPrice());

		if (learner.goodEnough()) {

			expectedLowestBid = learner.act() - learner.getStdDev();
			expectedHighestAsk = learner.act() + learner.getStdDev();

			ReportVariableBoard.getInstance().reportValue(
					SLIDING_AVERAGE_TRANSACTION_PRICE, learner.act());
		}

        logger.info("expectedLowestBid:" + expectedLowestBid);
        logger.info("expectedHighestAsk:" + expectedHighestAsk);
        logger.info("\n");
	}
    
    private void dayClosed(AuctionEvent event) {
            /*
        Score dailyScore = scoreReport.getDailyScore(getAuctioneer().getName());

        try {

            currentTransactionRate = dailyScore.transactionRate;
            currentProfit = dailyScore.profitShare;
            currentMarketShare = dailyScore.marketShare;
            currentTotal = dailyScore.total;

        } catch (NullPointerException e) {

            logger.info("currentTransactionRate: NULL");

        } finally {

            logger.info("SpecialistId:" + getAuctioneer().getName());
            logger.info("dailyScore:" + scoreReport.getScore(getAuctioneer().getName()));

        }

        if(currentTransactionRate < lastTransactionRate && currentTotal > lastTotal){
            k = k - stepK;
        }

        if(currentTransactionRate > lastTransactionRate && currentTotal < lastTotal){
            k = k + stepK;
        }

        if (k > maxK) k = maxK;
        if (k < minK ) k = minK;
			
        lastTransactionRate = currentTransactionRate;
		lastProfit = currentProfit;
        lastMarketShare = currentMarketShare;
		lastTotal = currentTotal;

		*/
        k= 0.1;
	}

    private void gameOver(AuctionEvent event) {

    roundPeriod = knowledgeAdaptive.nowRoundAtPeriod();

        if(roundPeriod.equals("expansion")){

			expectedLowestBid = expectedLowestBid * (1-k);
			expectedHighestAsk = expectedHighestAsk * (1+k);

		}else if(roundPeriod.equals("convergence")){
		
			expectedLowestBid = expectedLowestBid * (1+(k/2));
			expectedHighestAsk = expectedHighestAsk * (1-(k/2));

		}else if(roundPeriod.equals("sprint")){

        }
	}
    
}
